﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.ClientRequest
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
using System.Threading;

namespace Microsoft.InfoCards
{
  internal abstract class ClientRequest : Request
  {
    private const int OutstandingCallWaitTime = 30000;
    private IDictionary m_asyncOps;
    private IDictionary m_cachedCerts;
    private Process m_callerProcess;
    private WindowsIdentity m_callerIdentity;
    private Dictionary<Type, object> m_contextBag;
    private object m_serviceAsyncSyncRoot;
    private ClientRequest.ServiceAsyncOperation m_serviceAsyncOperation;
    private bool m_cancelled;
    private bool m_untrusted;

    public static Process GetCallingProcessFromRpcHandle(IntPtr RpcHandle)
    {
      uint pid;
      if (NativeMethods.I_RpcBindingInqLocalClientPID(RpcHandle, out pid) != 0U)
        throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceErrorGettingClientPid")));
      Process process = (Process) null;
      bool flag1 = false;
      bool flag2 = false;
      while (!flag1)
      {
        flag1 = true;
        try
        {
          if (flag2)
            NativeMcppMethods.AddSystemAccessToProcess(RpcHandle, pid);
          process = ProcessMonitor.GetProcessById((int) pid);
        }
        catch (ArgumentException ex)
        {
          throw InfoCardTrace.ThrowHelperError((Exception) new UserCancelledException());
        }
        catch (Win32Exception ex)
        {
          bool flag3 = false;
          if (5 == ex.NativeErrorCode && !flag2)
          {
            flag1 = false;
            flag2 = true;
            flag3 = true;
          }
          if (!flag3)
            throw InfoCardTrace.ThrowHelperError((Exception) new SecurityException(SR.GetString("ClientAPIInfocardError"), (Exception) ex));
        }
      }
      return process;
    }

    public ClientRequest(
      Process callingProcess,
      WindowsIdentity userIdentity,
      IntPtr rpcHandle,
      Stream inArgs,
      Stream outArgs)
      : this(callingProcess, userIdentity, rpcHandle, inArgs, outArgs, ExceptionList.AllNonFatal)
    {
    }

    public ClientRequest(
      Process callingProcess,
      WindowsIdentity callingIdentity,
      IntPtr rpcHandle,
      Stream inArgs,
      Stream outArgs,
      ExceptionList recoverableExceptions)
      : base(rpcHandle, inArgs, outArgs, recoverableExceptions)
    {
      InfoCardTrace.ThrowInvalidArgumentConditional(null == callingProcess, nameof (callingProcess));
      InfoCardTrace.ThrowInvalidArgumentConditional(null == callingIdentity, "userIdentity");
      InfoCardTrace.ThrowInvalidArgumentConditional(IntPtr.Zero == rpcHandle, nameof (rpcHandle));
      InfoCardTrace.ThrowInvalidArgumentConditional(null == inArgs, nameof (inArgs));
      InfoCardTrace.ThrowInvalidArgumentConditional(null == outArgs, nameof (outArgs));
      this.m_callerProcess = callingProcess;
      this.m_callerIdentity = callingIdentity;
      this.m_contextBag = new Dictionary<Type, object>();
      this.m_serviceAsyncSyncRoot = new object();
      InfoCardService.LifeTimeMonitor.AddClient();
    }

    public override WindowsIdentity RequestorIdentity
    {
      get
      {
        return this.m_callerIdentity;
      }
    }

    public Process CallerProcess
    {
      get
      {
        return this.m_callerProcess;
      }
    }

    public uint CallerPid
    {
      get
      {
        return (uint) this.CallerProcess.Id;
      }
    }

    protected override void OnInitializeAsSystem()
    {
      if (this.CallerProcess.HasExited)
        throw InfoCardTrace.ThrowHelperError((Exception) new UserCancelledException());
    }

    public T GetContext<T>()
    {
      object obj = (object) null;
      if (this.m_contextBag.TryGetValue(typeof (T), out obj))
        return (T) obj;
      return default (T);
    }

    public void SetContext<T>(T value)
    {
      this.m_contextBag[typeof (T)] = (object) value;
    }

    public void ClearContext<T>()
    {
      this.m_contextBag.Remove(typeof (T));
    }

    public void AddAsyncOp(RpcAsyncResult async)
    {
      lock (this.SyncRoot)
      {
        if (this.m_asyncOps == null)
          this.m_asyncOps = (IDictionary) new HybridDictionary();
        this.m_asyncOps[(object) async.Handle] = (object) async;
      }
    }

    public void CancelAsyncOp(int handle)
    {
      lock (this.SyncRoot)
      {
        if (this.m_asyncOps == null || !this.m_asyncOps.Contains((object) handle))
          return;
        ((RpcAsyncResult) this.m_asyncOps[(object) handle]).Cancel();
      }
    }

    public void RemoveAsyncOp(int handle)
    {
      lock (this.SyncRoot)
        this.m_asyncOps.Remove((object) handle);
    }

    private RpcAsyncResult FindAsyncOp(int handle)
    {
      lock (this.SyncRoot)
        return (RpcAsyncResult) this.m_asyncOps[(object) handle];
    }

    protected void CheckIfAllAsyncOpsCompleted()
    {
      lock (this.SyncRoot)
      {
        if (this.m_asyncOps == null)
          return;
        foreach (RpcAsyncResult rpcAsyncResult in (IEnumerable) this.m_asyncOps.Values)
          ;
      }
    }

    public RpcAsyncResult WaitForAsyncCompletion(int handle)
    {
      RpcAsyncResult asyncOp = this.FindAsyncOp(handle);
      if (asyncOp == null)
        throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceInvalidAsyncHandle")));
      asyncOp.AsyncWaitHandle.WaitOne();
      Exception exception = asyncOp.Exception;
      if (exception != null)
        throw new InfoCardRequestException(SR.GetString("ServiceAsyncOpGeneratedException"), exception);
      return asyncOp;
    }

    public void CertCacheAdd(string recipientIdentifier, X509Certificate2 cert)
    {
      lock (this.SyncRoot)
      {
        if (this.m_cachedCerts == null)
          this.m_cachedCerts = (IDictionary) new HybridDictionary();
        this.m_cachedCerts[(object) recipientIdentifier] = (object) cert;
      }
    }

    public X509Certificate2 CertCacheFind(string recipientId)
    {
      lock (this.SyncRoot)
        return (X509Certificate2) this.m_cachedCerts[(object) recipientId];
    }

    public static uint Authorize(IntPtr rpcIfHandle, IntPtr context)
    {
      uint num = 5;
      InfoCardTrace.ThrowInvalidArgumentConditional(IntPtr.Zero == rpcIfHandle, nameof (rpcIfHandle));
      InfoCardTrace.ThrowInvalidArgumentConditional(IntPtr.Zero == context, nameof (context));
      try
      {
        using (WindowsIdentity windowsIdentity = Utility.GetWindowsIdentity(context))
        {
          if (!windowsIdentity.IsAuthenticated)
            throw InfoCardTrace.ThrowHelperError((Exception) new SecurityException());
          if (!ClientRequest.ValidateToken(context, windowsIdentity))
            throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceInvalidCallerToken")));
          num = 0U;
        }
      }
      catch (RuntimeWrappedException ex)
      {
        InfoCardTrace.TraceAndLogException((Exception) ex);
        InfoCardService.Crash();
      }
      catch (SecurityException ex)
      {
        InfoCardTrace.Assert(5U == num, "Unexpected value for err!");
      }
      catch (InfoCardBaseException ex)
      {
        throw;
      }
      catch (Exception ex)
      {
        if (InfoCardTrace.IsFatal(ex))
          InfoCardService.Crash(ex);
        throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("ServiceUnableToValidateCallerToken", (object) ex.Message)));
      }
      return num;
    }

    private static bool ValidateToken(IntPtr rpcItfHandle, WindowsIdentity rpcIdentity)
    {
      Process processFromRpcHandle = ClientRequest.GetCallingProcessFromRpcHandle(rpcItfHandle);
      bool flag = NativeMcppMethods.CreateServiceExecutionIdentity(processFromRpcHandle).User.Value == rpcIdentity.User.Value;
      if (flag)
        flag = NativeMcppMethods.IsTokenValid(processFromRpcHandle);
      return flag;
    }

    protected override void OnDisposeAsSystem()
    {
      this.m_callerProcess = (Process) null;
      object[] objArray = (object[]) null;
      lock (this.SyncRoot)
      {
        if (this.m_asyncOps != null)
        {
          objArray = new object[this.m_asyncOps.Values.Count];
          this.m_asyncOps.Values.CopyTo((Array) objArray, 0);
        }
      }
      if (objArray != null)
      {
        foreach (RpcAsyncResult rpcAsyncResult in objArray)
          rpcAsyncResult.Dispose();
      }
      InfoCardService.LifeTimeMonitor.RemoveClient();
      base.OnDisposeAsSystem();
    }

    protected void ExecuteCancelable(
      ClientRequest.AsyncEntryCallback entry,
      ClientRequest.AsyncEntryCallback cancel)
    {
      lock (this.m_serviceAsyncSyncRoot)
      {
        if (this.m_cancelled)
        {
          if (this.m_untrusted)
            throw InfoCardTrace.ThrowHelperError((Exception) new UntrustedRecipientException());
          throw InfoCardTrace.ThrowHelperError((Exception) new UserCancelledException());
        }
        InfoCardTrace.Assert(null == this.m_serviceAsyncOperation, "Only a single cancelable service operation can be running at a time");
        this.m_serviceAsyncOperation = new ClientRequest.ServiceAsyncOperation(entry, cancel);
        try
        {
          if (!ThreadPool.QueueUserWorkItem(InfoCardTrace.ThunkCallback(new WaitCallback(ClientRequest.ServiceAsyncEntry)), (object) this.m_serviceAsyncOperation))
            throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(SR.GetString("UnableToQueueThreadpool")));
          this.m_serviceAsyncOperation.WaitForCompletion();
          if (this.m_serviceAsyncOperation.WasCancelled)
          {
            if (this.m_untrusted)
              throw InfoCardTrace.ThrowHelperError((Exception) new UntrustedRecipientException());
            throw InfoCardTrace.ThrowHelperError((Exception) new UserCancelledException());
          }
          if (this.m_serviceAsyncOperation.ExecutionException != null)
            throw InfoCardTrace.ThrowHelperError((Exception) new CommunicationException(this.m_serviceAsyncOperation.ExecutionException.Message, this.m_serviceAsyncOperation.ExecutionException));
        }
        finally
        {
          this.m_serviceAsyncOperation = (ClientRequest.ServiceAsyncOperation) null;
        }
      }
    }

    protected void CancelServiceAsyncOperation(bool untrusted)
    {
      if (this.m_serviceAsyncOperation != null)
        this.m_serviceAsyncOperation.Cancel();
      this.m_untrusted = untrusted;
      this.m_cancelled = true;
    }

    private static void ServiceAsyncEntry(object state)
    {
      ClientRequest.ServiceAsyncOperation serviceAsyncOperation = (ClientRequest.ServiceAsyncOperation) state;
      try
      {
        serviceAsyncOperation.Execute();
      }
      finally
      {
        serviceAsyncOperation.Complete();
      }
    }

    internal delegate void AsyncEntryCallback();

    private class ServiceAsyncOperation
    {
      private ClientRequest.AsyncEntryCallback m_cancelCallback;
      private ClientRequest.AsyncEntryCallback m_entryCallback;
      private ManualResetEvent m_syncEvent;
      private Exception m_exception;
      private bool m_complete;
      private bool m_cancelled;
      private object m_sync;

      public ServiceAsyncOperation(
        ClientRequest.AsyncEntryCallback entry,
        ClientRequest.AsyncEntryCallback cancel)
      {
        this.m_entryCallback = entry;
        this.m_cancelCallback = cancel;
        this.m_sync = new object();
        this.m_syncEvent = new ManualResetEvent(false);
      }

      public bool WasCancelled
      {
        get
        {
          return this.m_cancelled;
        }
      }

      public Exception ExecutionException
      {
        get
        {
          return this.m_exception;
        }
      }

      public void Complete()
      {
        if (this.m_complete)
          return;
        lock (this.m_sync)
        {
          if (this.m_complete)
            return;
          this.m_complete = true;
          this.m_syncEvent.Set();
        }
      }

      public void WaitForCompletion()
      {
        this.m_syncEvent.WaitOne();
      }

      public void Execute()
      {
        lock (this.m_sync)
        {
          if (this.m_cancelled)
            return;
          this.m_complete = false;
          this.m_syncEvent.Reset();
        }
        try
        {
          this.m_entryCallback();
        }
        catch (Exception ex)
        {
          if (InfoCardTrace.IsFatal(ex))
            InfoCardService.Crash(ex);
          else
            this.m_exception = ex;
        }
      }

      public void Cancel()
      {
        lock (this.m_sync)
        {
          if (this.m_complete)
            return;
          this.m_cancelled = true;
          try
          {
            if (this.m_cancelCallback == null)
              return;
            this.m_cancelCallback();
          }
          finally
          {
            this.Complete();
          }
        }
      }
    }
  }
}
